﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ICeFramework.Win.UI
{
    public partial class ICTreeView : TreeView
    {
        public delegate void ValidateLabelEditEventHandler(object sender, ValidateLabelEditEventArgs e);

        private const int WM_TIMER = 0x0113;
        private bool TriggerLabelEdit = false;
        private string viewedLabel;
        private string editedLabel;

        public event ValidateLabelEditEventHandler ValidateLabelEdit;

        #region public ICTreeView()
        /// <summary>
        /// Initializes a new instance of the <b>ICTreeView</b> class.
        /// </summary>
        public ICTreeView()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.EnableNotifyMessage, true);
        }
        #endregion

        #region public ICTreeView(IContainer container)
        /// <summary>
        /// Initializes a new instance of the <b>ICTreeView</b> class.
        /// </summary>
        /// <param name="container"></param>
        public ICTreeView(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
            this.SetStyle(ControlStyles.EnableNotifyMessage, true);
        }
        #endregion

        #region protected override void OnMouseDown(MouseEventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                TreeNode tn = this.GetNodeAt(e.X, e.Y);
                if (tn != null)
                    this.SelectedNode = tn;
            }
            base.OnMouseDown(e);
        }
        #endregion

        #region protected override void OnKeyDown(KeyEventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            if (this.LabelEdit && e.KeyCode == Keys.F2 && e.Alt == false && e.Control == false && e.Shift == false)
            {
                BeginEdit();
            }
        }
        #endregion

        #region protected override void OnMouseUp(MouseEventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            TreeNode tn;
            if (e.Button == MouseButtons.Left)
            {
                tn = this.SelectedNode;
                if (tn == this.GetNodeAt(e.X, e.Y))
                {
                    if (wasDoubleClick)
                        wasDoubleClick = false;
                    else if (this.LabelEdit)
                    {
                        TriggerLabelEdit = true;
                    }
                }
            }
            base.OnMouseUp(e);
        }
        #endregion

        #region protected override void OnBeforeLabelEdit(NodeLabelEditEventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnBeforeLabelEdit(NodeLabelEditEventArgs e)
        {
            // put node label to initial state
            // to ensure that in case of label editing cancelled
            // the initial state of label is preserved
            this.SelectedNode.Text = viewedLabel;
            // base.OnBeforeLabelEdit is not called here
            // it is called only from StartLabelEdit
        }
        #endregion

        #region protected override void OnAfterLabelEdit(NodeLabelEditEventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnAfterLabelEdit(NodeLabelEditEventArgs e)
        {
            //this.LabelEdit = false;
            e.CancelEdit = true;
            if (e.Label == null)
            {
                return;
            }
            ValidateLabelEditEventArgs ea = new ValidateLabelEditEventArgs(e.Label);
            OnValidateLabelEdit(ea);
            if (ea.Cancel == true)
            {
                e.Node.Text = editedLabel;
                this.LabelEdit = true;
                e.Node.BeginEdit();
            }
            else
            {
                base.OnAfterLabelEdit(e);
            }
        }
        #endregion

        #region public void BeginEdit()
        /// <summary>
        /// 
        /// </summary>
        public void BeginEdit()
        {
            StartLabelEdit();
        }
        #endregion

        #region protected override void OnNotifyMessage(Message m)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="m"></param>
        protected override void OnNotifyMessage(Message m)
        {
            if (TriggerLabelEdit)
                if (m.Msg == WM_TIMER)
                {
                    TriggerLabelEdit = false;
                    StartLabelEdit();
                }
            base.OnNotifyMessage(m);
        }
        #endregion

        #region public void StartLabelEdit()
        /// <summary>
        /// 
        /// </summary>
        public void StartLabelEdit()
        {
            TreeNode tn = this.SelectedNode;
            viewedLabel = tn.Text;

            NodeLabelEditEventArgs e = new NodeLabelEditEventArgs(tn);
            base.OnBeforeLabelEdit(e);

            if (e.CancelEdit == true)
            {
                return;
            }
            editedLabel = tn.Text;

            this.LabelEdit = true;
            tn.BeginEdit();
        }
        #endregion

        #region protected override void OnClick(EventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClick(EventArgs e)
        {
            TriggerLabelEdit = false;
            base.OnClick(e);
        }
        #endregion

        private bool wasDoubleClick = false;
        #region protected override void OnDoubleClick(EventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnDoubleClick(EventArgs e)
        {
            wasDoubleClick = true;
            base.OnDoubleClick(e);
        }
        #endregion

        #region protected virtual void OnValidateLabelEdit(ValidateLabelEditEventArgs e)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnValidateLabelEdit(ValidateLabelEditEventArgs e)
        {
            if (ValidateLabelEdit != null)
            {
                ValidateLabelEdit(this, e);
            }
        }
        #endregion
    }

    #region public class ValidateLabelEditEventArgs : CancelEventArgs
    /// <summary>
    /// 
    /// </summary>
    /// <remarks></remarks>
    /// <example></example>
    public class ValidateLabelEditEventArgs : CancelEventArgs
    {
        private string _label;
        #region public string Label
        /// <summary>
        /// Get/Sets the Label of the ValidateLabelEditEventArgs
        /// </summary>
        /// <value></value>
        public string Label
        {
            get { return _label; }
            set { _label = value; }
        }
        #endregion

        #region public ValidateLabelEditEventArgs(string label)
        /// <summary>
        /// Initializes a new instance of the <b>ValidateLabelEditEventArgs</b> class.
        /// </summary>
        /// <param name="label"></param>
        public ValidateLabelEditEventArgs(string label)
        {
            _label = label;
            this.Cancel = false;
        }
        #endregion


    }
    #endregion

    public class ICTreeNode : TreeNode
    {
        private object _additionalData;
        public object AdditionalData
        {
            get { return _additionalData; }
            set { _additionalData = value; }
        }
    }
}
